baubs git
Commit 2b5e1d763b0b47d79099976dbbb35f6d2d7fac63
Parents : 3ec9dda
Author : Jan-Henrik Bruhn <jan-henrik.bruhn@offis.de>
Date : 2025-12-26T22:48:25+01:00
fix: Store original and uploaded pattern data to prevent rotation inconsistencies
Store both original unrotated pesData and uploaded rotated pesData in cache
to ensure exact consistency on resume and prevent issues from algorithm changes
between versions. This fixes rotation/position reset issues after page reload.
- Cache original unrotated pattern + rotation angle for editing
- Cache exact uploaded pattern data sent to machine
- Restore original offset after loading cached pattern
- Use cached uploaded data on resume instead of recalculating
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changes
12 files changed, 287 insertions(+), 36 deletions(-)
Diff
diff --git a/src/App.tsx b/src/App.tsx
index f732876..5d6689d 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -8,6 +8,13 @@ import { LeftSidebar } from "./components/LeftSidebar";
import { PatternCanvas } from "./components/PatternCanvas";
import { PatternCanvasPlaceholder } from "./components/PatternCanvasPlaceholder";
import { BluetoothDevicePicker } from "./components/BluetoothDevicePicker";
+import { transformStitchesRotation } from "./utils/rotationUtils";
+import { encodeStitchesToPen } from "./formats/pen/encoder";
+import { decodePenData } from "./formats/pen/decoder";
+import {
+ calculatePatternCenter,
+ calculateBoundsFromDecodedStitches,
+} from "./components/PatternCanvas/patternCanvasHelpers";
import "./App.css";
function App() {
@@ -25,10 +32,20 @@ function App() {
);
// Pattern store - for auto-loading cached pattern
- const { pesData, setPattern, setPatternOffset } = usePatternStore(
+ const {
+ pesData,
+ uploadedPesData,
+ setPattern,
+ setUploadedPattern,
+ setPatternRotation,
+ setPatternOffset,
+ } = usePatternStore(
useShallow((state) => ({
pesData: state.pesData,
+ uploadedPesData: state.uploadedPesData,
setPattern: state.setPattern,
+ setUploadedPattern: state.setUploadedPattern,
+ setPatternRotation: state.setPatternRotation,
setPatternOffset: state.setPatternOffset,
})),
);
@@ -47,23 +64,130 @@ function App() {
// Auto-load cached pattern when available
useEffect(() => {
- if (resumedPattern && !pesData) {
+ // Only auto-load if we have a resumed pattern and haven't already loaded it
+ if (resumedPattern && !uploadedPesData && !pesData) {
+ if (!resumedPattern.pesData) {
+ console.error(
+ "[App] ERROR: resumedPattern has no pesData!",
+ resumedPattern,
+ );
+ return;
+ }
+
console.log(
"[App] Loading resumed pattern:",
resumeFileName,
"Offset:",
resumedPattern.patternOffset,
+ "Rotation:",
+ resumedPattern.patternRotation,
+ "Has stitches:",
+ resumedPattern.pesData.stitches?.length || 0,
+ "Has cached uploaded data:",
+ !!resumedPattern.uploadedPesData,
);
- setPattern(resumedPattern.pesData, resumeFileName || "");
- // Restore the cached pattern offset
- if (resumedPattern.patternOffset) {
- setPatternOffset(
- resumedPattern.patternOffset.x,
- resumedPattern.patternOffset.y,
+
+ const originalPesData = resumedPattern.pesData;
+ const cachedUploadedPesData = resumedPattern.uploadedPesData;
+ const rotation = resumedPattern.patternRotation || 0;
+ const originalOffset = resumedPattern.patternOffset || { x: 0, y: 0 };
+
+ // Set the original pattern data for editing
+ setPattern(originalPesData, resumeFileName || "");
+
+ // Restore the original offset (setPattern resets it to 0,0)
+ setPatternOffset(originalOffset.x, originalOffset.y);
+
+ // Set rotation if present
+ if (rotation !== 0) {
+ setPatternRotation(rotation);
+ }
+
+ // Use cached uploadedPesData if available, otherwise recalculate
+ if (cachedUploadedPesData) {
+ // Use the exact uploaded data from cache
+ // Calculate the adjusted offset (same logic as upload)
+ if (rotation !== 0) {
+ const originalCenter = calculatePatternCenter(originalPesData.bounds);
+ const rotatedCenter = calculatePatternCenter(
+ cachedUploadedPesData.bounds,
+ );
+ const centerShiftX = rotatedCenter.x - originalCenter.x;
+ const centerShiftY = rotatedCenter.y - originalCenter.y;
+
+ const adjustedOffset = {
+ x: originalOffset.x + centerShiftX,
+ y: originalOffset.y + centerShiftY,
+ };
+
+ setUploadedPattern(
+ cachedUploadedPesData,
+ adjustedOffset,
+ resumeFileName || undefined,
+ );
+ } else {
+ setUploadedPattern(
+ cachedUploadedPesData,
+ originalOffset,
+ resumeFileName || undefined,
+ );
+ }
+ } else if (rotation !== 0) {
+ // Fallback: recalculate if no cached uploaded data (shouldn't happen for new uploads)
+ console.warn("[App] No cached uploaded data, recalculating rotation");
+ const rotatedStitches = transformStitchesRotation(
+ originalPesData.stitches,
+ rotation,
+ originalPesData.bounds,
+ );
+
+ const penResult = encodeStitchesToPen(rotatedStitches);
+ const penData = new Uint8Array(penResult.penBytes);
+ const decoded = decodePenData(penData);
+ const rotatedBounds = calculateBoundsFromDecodedStitches(decoded);
+
+ const originalCenter = calculatePatternCenter(originalPesData.bounds);
+ const rotatedCenter = calculatePatternCenter(rotatedBounds);
+ const centerShiftX = rotatedCenter.x - originalCenter.x;
+ const centerShiftY = rotatedCenter.y - originalCenter.y;
+
+ const adjustedOffset = {
+ x: originalOffset.x + centerShiftX,
+ y: originalOffset.y + centerShiftY,
+ };
+
+ const rotatedPesData = {
+ ...originalPesData,
+ stitches: rotatedStitches,
+ penData,
+ penStitches: decoded,
+ bounds: rotatedBounds,
+ };
+
+ setUploadedPattern(
+ rotatedPesData,
+ adjustedOffset,
+ resumeFileName || undefined,
+ );
+ } else {
+ // No rotation - uploaded pattern is same as original
+ setUploadedPattern(
+ originalPesData,
+ originalOffset,
+ resumeFileName || undefined,
);
}
}
- }, [resumedPattern, resumeFileName, pesData, setPattern, setPatternOffset]);
+ }, [
+ resumedPattern,
+ resumeFileName,
+ uploadedPesData,
+ pesData,
+ setPattern,
+ setUploadedPattern,
+ setPatternRotation,
+ setPatternOffset,
+ ]);
return (
<div className="h-screen flex flex-col bg-gray-100 dark:bg-gray-900 overflow-hidden">
@@ -76,7 +200,11 @@ function App() {
{/* Right Column - Pattern Preview */}
<div className="flex flex-col lg:overflow-hidden lg:h-full">
- {pesData ? <PatternCanvas /> : <PatternCanvasPlaceholder />}
+ {pesData || uploadedPesData ? (
+ <PatternCanvas />
+ ) : (
+ <PatternCanvasPlaceholder />
+ )}
</div>
</div>
diff --git a/src/components/FileUpload.tsx b/src/components/FileUpload.tsx
index 2f7e54e..0adad6a 100644
--- a/src/components/FileUpload.tsx
+++ b/src/components/FileUpload.tsx
@@ -206,11 +206,14 @@ export function FileUpload() {
setUploadedPattern(pesDataForUpload, adjustedOffset);
// Upload the pattern with offset
+ // IMPORTANT: Pass original unrotated pesData for caching, rotated pesData for upload
uploadPattern(
penDataToUpload,
pesDataForUpload,
displayFileName,
adjustedOffset,
+ patternRotation,
+ pesData, // Original unrotated pattern for caching
);
return; // Early return to skip the upload below
@@ -226,6 +229,8 @@ export function FileUpload() {
pesDataForUpload,
displayFileName,
patternOffset,
+ 0, // No rotation
+ // No need to pass originalPesData since it's the same as pesDataForUpload
);
}
}, [
diff --git a/src/components/LeftSidebar.tsx b/src/components/LeftSidebar.tsx
index adddb0e..01abd0f 100644
--- a/src/components/LeftSidebar.tsx
+++ b/src/components/LeftSidebar.tsx
@@ -13,14 +13,16 @@ export function LeftSidebar() {
})),
);
- const { pesData } = usePatternStore(
+ const { pesData, uploadedPesData } = usePatternStore(
useShallow((state) => ({
pesData: state.pesData,
+ uploadedPesData: state.uploadedPesData,
})),
);
// Derived state: pattern is uploaded if machine has pattern info
const patternUploaded = usePatternUploaded();
+ const hasPattern = pesData || uploadedPesData;
return (
<div className="flex flex-col gap-4 md:gap-5 lg:gap-6 lg:overflow-hidden">
@@ -31,7 +33,7 @@ export function LeftSidebar() {
{isConnected && !patternUploaded && <FileUpload />}
{/* Compact Pattern Summary - Show after upload (during sewing stages) */}
- {isConnected && patternUploaded && pesData && <PatternSummaryCard />}
+ {isConnected && patternUploaded && hasPattern && <PatternSummaryCard />}
{/* Progress Monitor - Show when pattern is uploaded */}
{isConnected && patternUploaded && (
diff --git a/src/components/PatternCanvas/PatternCanvas.tsx b/src/components/PatternCanvas/PatternCanvas.tsx
index b44d3a9..1756186 100644
--- a/src/components/PatternCanvas/PatternCanvas.tsx
+++ b/src/components/PatternCanvas/PatternCanvas.tsx
@@ -190,7 +190,9 @@ export function PatternCanvas() {
</Layer>
{/* Original pattern layer: draggable with transformer (shown before upload starts) */}
- <Layer visible={!isUploading && !patternUploaded}>
+ <Layer
+ visible={!isUploading && !patternUploaded && !uploadedPesData}
+ >
{pesData && (
<PatternLayer
pesData={pesData}
@@ -209,7 +211,9 @@ export function PatternCanvas() {
</Layer>
{/* Uploaded pattern layer: locked, rotation baked in (shown during and after upload) */}
- <Layer visible={isUploading || patternUploaded}>
+ <Layer
+ visible={isUploading || patternUploaded || !!uploadedPesData}
+ >
{uploadedPesData && (
<PatternLayer
pesData={uploadedPesData}
@@ -241,12 +245,12 @@ export function PatternCanvas() {
<PatternPositionIndicator
offset={
- isUploading || patternUploaded
+ isUploading || patternUploaded || uploadedPesData
? initialUploadedPatternOffset
: localPatternOffset
}
rotation={localPatternRotation}
- isLocked={patternUploaded}
+ isLocked={patternUploaded || !!uploadedPesData}
isUploading={isUploading}
/>
@@ -257,7 +261,10 @@ export function PatternCanvas() {
onZoomReset={handleZoomReset}
onCenterPattern={handleCenterPattern}
canCenterPattern={
- !!pesData && !patternUploaded && !isUploading
+ !!pesData &&
+ !patternUploaded &&
+ !isUploading &&
+ !uploadedPesData
}
/>
</>
diff --git a/src/components/PatternSummaryCard.tsx b/src/components/PatternSummaryCard.tsx
index 71874c5..ec02865 100644
--- a/src/components/PatternSummaryCard.tsx
+++ b/src/components/PatternSummaryCard.tsx
@@ -25,14 +25,16 @@ export function PatternSummaryCard() {
);
// Pattern store
- const { pesData, currentFileName } = usePatternStore(
+ const { pesData, uploadedPesData, currentFileName } = usePatternStore(
useShallow((state) => ({
pesData: state.pesData,
+ uploadedPesData: state.uploadedPesData,
currentFileName: state.currentFileName,
})),
);
- if (!pesData) return null;
+ const displayPattern = uploadedPesData || pesData;
+ if (!displayPattern) return null;
const canDelete = canDeletePattern(machineStatus);
return (
@@ -52,7 +54,7 @@ export function PatternSummaryCard() {
</div>
</CardHeader>
<CardContent className="px-4 pt-0 pb-4">
- <PatternInfo pesData={pesData} />
+ <PatternInfo pesData={displayPattern} />
{canDelete && (
<Button
diff --git a/src/components/ProgressMonitor.tsx b/src/components/ProgressMonitor.tsx
index 599312f..26fea1f 100644
--- a/src/components/ProgressMonitor.tsx
+++ b/src/components/ProgressMonitor.tsx
@@ -52,6 +52,8 @@ export function ProgressMonitor() {
// Pattern store
const pesData = usePatternStore((state) => state.pesData);
+ const uploadedPesData = usePatternStore((state) => state.uploadedPesData);
+ const displayPattern = uploadedPesData || pesData;
const currentBlockRef = useRef<HTMLDivElement>(null);
// State indicators
@@ -60,8 +62,8 @@ export function ProgressMonitor() {
// Use PEN stitch count as fallback when machine reports 0 total stitches
const totalStitches = patternInfo
- ? patternInfo.totalStitches === 0 && pesData?.penStitches
- ? pesData.penStitches.stitches.length
+ ? patternInfo.totalStitches === 0 && displayPattern?.penStitches
+ ? displayPattern.penStitches.stitches.length
: patternInfo.totalStitches
: 0;
@@ -72,7 +74,7 @@ export function ProgressMonitor() {
// Calculate color block information from decoded penStitches
const colorBlocks = useMemo(() => {
- if (!pesData || !pesData.penStitches) return [];
+ if (!displayPattern || !displayPattern.penStitches) return [];
const blocks: Array<{
colorIndex: number;
@@ -87,8 +89,8 @@ export function ProgressMonitor() {
}> = [];
// Use the pre-computed color blocks from decoded PEN data
- for (const penBlock of pesData.penStitches.colorBlocks) {
- const thread = pesData.threads[penBlock.colorIndex];
+ for (const penBlock of displayPattern.penStitches.colorBlocks) {
+ const thread = displayPattern.threads[penBlock.colorIndex];
blocks.push({
colorIndex: penBlock.colorIndex,
threadHex: thread?.hex || "#000000",
@@ -103,7 +105,7 @@ export function ProgressMonitor() {
}
return blocks;
- }, [pesData]);
+ }, [displayPattern]);
// Determine current color block based on current stitch
const currentStitch = sewingProgress?.currentStitch || 0;
diff --git a/src/platform/browser/BrowserStorageService.ts b/src/platform/browser/BrowserStorageService.ts
index 6d73ffb..c560526 100644
--- a/src/platform/browser/BrowserStorageService.ts
+++ b/src/platform/browser/BrowserStorageService.ts
@@ -15,8 +15,10 @@ export class BrowserStorageService implements IStorageService {
pesData: PesPatternData,
fileName: string,
patternOffset?: { x: number; y: number },
+ patternRotation?: number,
+ uploadedPesData?: PesPatternData,
): Promise<void> {
- PatternCacheService.savePattern(uuid, pesData, fileName, patternOffset);
+ PatternCacheService.savePattern(uuid, pesData, fileName, patternOffset, patternRotation, uploadedPesData);
}
async getPatternByUUID(uuid: string): Promise<ICachedPattern | null> {
diff --git a/src/platform/electron/ElectronStorageService.ts b/src/platform/electron/ElectronStorageService.ts
index acf7fb2..6bf4c48 100644
--- a/src/platform/electron/ElectronStorageService.ts
+++ b/src/platform/electron/ElectronStorageService.ts
@@ -20,6 +20,8 @@ export class ElectronStorageService implements IStorageService {
pesData: PesPatternData,
fileName: string,
patternOffset?: { x: number; y: number },
+ patternRotation?: number,
+ uploadedPesData?: PesPatternData,
): Promise<void> {
// Convert Uint8Array to array for JSON serialization over IPC
const serializable = {
@@ -28,9 +30,16 @@ export class ElectronStorageService implements IStorageService {
...pesData,
penData: Array.from(pesData.penData),
},
+ uploadedPesData: uploadedPesData
+ ? {
+ ...uploadedPesData,
+ penData: Array.from(uploadedPesData.penData),
+ }
+ : undefined,
fileName,
timestamp: Date.now(),
patternOffset,
+ patternRotation,
};
// Fire and forget (sync-like behavior to match interface)
@@ -51,6 +60,11 @@ export class ElectronStorageService implements IStorageService {
pattern.pesData.penData = new Uint8Array(pattern.pesData.penData);
}
+ if (pattern && pattern.uploadedPesData && Array.isArray(pattern.uploadedPesData.penData)) {
+ // Restore Uint8Array from array for uploadedPesData
+ pattern.uploadedPesData.penData = new Uint8Array(pattern.uploadedPesData.penData);
+ }
+
return pattern;
} catch (err) {
console.error("[ElectronStorage] Failed to get pattern:", err);
@@ -69,6 +83,11 @@ export class ElectronStorageService implements IStorageService {
pattern.pesData.penData = new Uint8Array(pattern.pesData.penData);
}
+ if (pattern && pattern.uploadedPesData && Array.isArray(pattern.uploadedPesData.penData)) {
+ // Restore Uint8Array from array for uploadedPesData
+ pattern.uploadedPesData.penData = new Uint8Array(pattern.uploadedPesData.penData);
+ }
+
return pattern;
} catch (err) {
console.error("[ElectronStorage] Failed to get latest pattern:", err);
diff --git a/src/platform/interfaces/IStorageService.ts b/src/platform/interfaces/IStorageService.ts
index 6154e77..f1af702 100644
--- a/src/platform/interfaces/IStorageService.ts
+++ b/src/platform/interfaces/IStorageService.ts
@@ -2,10 +2,12 @@ import type { PesPatternData } from "../../formats/import/pesImporter";
export interface ICachedPattern {
uuid: string;
- pesData: PesPatternData;
+ pesData: PesPatternData; // Original unrotated pattern data
+ uploadedPesData?: PesPatternData; // Pattern with rotation applied (what was uploaded to machine)
fileName: string;
timestamp: number;
patternOffset?: { x: number; y: number };
+ patternRotation?: number; // Rotation angle in degrees
}
export interface IStorageService {
@@ -14,6 +16,8 @@ export interface IStorageService {
pesData: PesPatternData,
fileName: string,
patternOffset?: { x: number; y: number },
+ patternRotation?: number,
+ uploadedPesData?: PesPatternData,
): Promise<void>;
getPatternByUUID(uuid: string): Promise<ICachedPattern | null>;
diff --git a/src/services/PatternCacheService.ts b/src/services/PatternCacheService.ts
index 2c11fe5..440197b 100644
--- a/src/services/PatternCacheService.ts
+++ b/src/services/PatternCacheService.ts
@@ -2,10 +2,12 @@ import type { PesPatternData } from "../formats/import/pesImporter";
interface CachedPattern {
uuid: string;
- pesData: PesPatternData;
+ pesData: PesPatternData; // Original unrotated pattern data
+ uploadedPesData?: PesPatternData; // Pattern with rotation applied (what was uploaded to machine)
fileName: string;
timestamp: number;
patternOffset?: { x: number; y: number };
+ patternRotation?: number; // Rotation angle in degrees
}
const CACHE_KEY = "brother_pattern_cache";
@@ -39,6 +41,8 @@ export class PatternCacheService {
pesData: PesPatternData,
fileName: string,
patternOffset?: { x: number; y: number },
+ patternRotation?: number,
+ uploadedPesData?: PesPatternData,
): void {
try {
// Convert penData Uint8Array to array for JSON serialization
@@ -47,12 +51,22 @@ export class PatternCacheService {
penData: Array.from(pesData.penData) as unknown as Uint8Array,
};
+ // Also convert uploadedPesData if present
+ const uploadedPesDataWithArrayPenData = uploadedPesData
+ ? {
+ ...uploadedPesData,
+ penData: Array.from(uploadedPesData.penData) as unknown as Uint8Array,
+ }
+ : undefined;
+
const cached: CachedPattern = {
uuid,
pesData: pesDataWithArrayPenData,
+ uploadedPesData: uploadedPesDataWithArrayPenData,
fileName,
timestamp: Date.now(),
patternOffset,
+ patternRotation,
};
localStorage.setItem(CACHE_KEY, JSON.stringify(cached));
@@ -63,6 +77,10 @@ export class PatternCacheService {
uuid,
"Offset:",
patternOffset,
+ "Rotation:",
+ patternRotation,
+ "Has uploaded data:",
+ !!uploadedPesData,
);
} catch (err) {
console.error("[PatternCache] Failed to save pattern:", err);
@@ -101,11 +119,18 @@ export class PatternCacheService {
pattern.pesData.penData = new Uint8Array(pattern.pesData.penData);
}
+ // Restore Uint8Array from array inside uploadedPesData if present
+ if (pattern.uploadedPesData && Array.isArray(pattern.uploadedPesData.penData)) {
+ pattern.uploadedPesData.penData = new Uint8Array(pattern.uploadedPesData.penData);
+ }
+
console.log(
"[PatternCache] Found cached pattern:",
pattern.fileName,
"UUID:",
uuid,
+ "Has uploaded data:",
+ !!pattern.uploadedPesData,
);
return pattern;
} catch (err) {
@@ -131,6 +156,11 @@ export class PatternCacheService {
pattern.pesData.penData = new Uint8Array(pattern.pesData.penData);
}
+ // Restore Uint8Array from array inside uploadedPesData if present
+ if (pattern.uploadedPesData && Array.isArray(pattern.uploadedPesData.penData)) {
+ pattern.uploadedPesData.penData = new Uint8Array(pattern.uploadedPesData.penData);
+ }
+
return pattern;
} catch (err) {
console.error("[PatternCache] Failed to retrieve pattern:", err);
diff --git a/src/stores/useMachineStore.ts b/src/stores/useMachineStore.ts
index 0ecef31..53308ed 100644
--- a/src/stores/useMachineStore.ts
+++ b/src/stores/useMachineStore.ts
@@ -43,7 +43,9 @@ interface MachineState {
resumeFileName: string | null;
resumedPattern: {
pesData: PesPatternData;
+ uploadedPesData?: PesPatternData;
patternOffset?: { x: number; y: number };
+ patternRotation?: number;
} | null;
// Error state
@@ -67,9 +69,11 @@ interface MachineState {
refreshServiceCount: () => Promise<void>;
uploadPattern: (
penData: Uint8Array,
- pesData: PesPatternData,
+ uploadedPesData: PesPatternData, // Pattern with rotation applied (for machine upload)
fileName: string,
patternOffset?: { x: number; y: number },
+ patternRotation?: number,
+ originalPesData?: PesPatternData, // Original unrotated pattern (for caching)
) => Promise<void>;
startMaskTrace: () => Promise<void>;
startSewing: () => Promise<void>;
@@ -78,7 +82,9 @@ interface MachineState {
checkResume: () => Promise<PesPatternData | null>;
loadCachedPattern: () => Promise<{
pesData: PesPatternData;
+ uploadedPesData?: PesPatternData;
patternOffset?: { x: number; y: number };
+ patternRotation?: number;
} | null>;
// Internal methods
@@ -137,6 +143,10 @@ export const useMachineStore = create<MachineState>((set, get) => ({
cached.fileName,
"Offset:",
cached.patternOffset,
+ "Rotation:",
+ cached.patternRotation,
+ "Has uploaded data:",
+ !!cached.uploadedPesData,
);
console.log("[Resume] Auto-loading cached pattern...");
set({
@@ -144,7 +154,9 @@ export const useMachineStore = create<MachineState>((set, get) => ({
resumeFileName: cached.fileName,
resumedPattern: {
pesData: cached.pesData,
+ uploadedPesData: cached.uploadedPesData,
patternOffset: cached.patternOffset,
+ patternRotation: cached.patternRotation,
},
});
@@ -302,9 +314,11 @@ export const useMachineStore = create<MachineState>((set, get) => ({
// Upload pattern to machine
uploadPattern: async (
penData: Uint8Array,
- pesData: PesPatternData,
+ uploadedPesData: PesPatternData, // Pattern with rotation applied (for machine upload)
fileName: string,
patternOffset?: { x: number; y: number },
+ patternRotation?: number,
+ originalPesData?: PesPatternData, // Original unrotated pattern (for caching)
) => {
const {
isConnected,
@@ -321,20 +335,31 @@ export const useMachineStore = create<MachineState>((set, get) => ({
try {
set({ error: null, uploadProgress: 0, isUploading: true });
+ // Upload to machine using the rotated bounds
const uuid = await service.uploadPattern(
penData,
(progress) => {
set({ uploadProgress: progress });
},
- pesData.bounds,
+ uploadedPesData.bounds,
patternOffset,
);
set({ uploadProgress: 100 });
- // Cache the pattern with its UUID and offset
+ // Cache the ORIGINAL unrotated pattern with rotation angle AND the uploaded data
+ // This allows us to restore the editable state correctly and ensures the exact
+ // uploaded data is used on resume (prevents inconsistencies from version updates)
+ const pesDataToCache = originalPesData || uploadedPesData;
const uuidStr = uuidToString(uuid);
- storageService.savePattern(uuidStr, pesData, fileName, patternOffset);
+ storageService.savePattern(
+ uuidStr,
+ pesDataToCache,
+ fileName,
+ patternOffset,
+ patternRotation,
+ uploadedPesData, // Cache the exact uploaded data
+ );
console.log(
"[Cache] Saved pattern:",
fileName,
@@ -342,6 +367,9 @@ export const useMachineStore = create<MachineState>((set, get) => ({
uuidStr,
"Offset:",
patternOffset,
+ "Rotation:",
+ patternRotation,
+ "(cached original unrotated data + uploaded data)",
);
// Clear resume state since we just uploaded
@@ -440,6 +468,7 @@ export const useMachineStore = create<MachineState>((set, get) => ({
uploadProgress: 0,
resumeAvailable: false,
resumeFileName: null,
+ resumedPattern: null, // Clear this to prevent auto-reload
});
// Clear uploaded pattern data in pattern store
@@ -458,7 +487,9 @@ export const useMachineStore = create<MachineState>((set, get) => ({
// Load cached pattern
loadCachedPattern: async (): Promise<{
pesData: PesPatternData;
+ uploadedPesData?: PesPatternData;
patternOffset?: { x: number; y: number };
+ patternRotation?: number;
} | null> => {
const { resumeAvailable, service, storageService, refreshPatternInfo } =
get();
@@ -477,9 +508,18 @@ export const useMachineStore = create<MachineState>((set, get) => ({
cached.fileName,
"Offset:",
cached.patternOffset,
+ "Rotation:",
+ cached.patternRotation,
+ "Has uploaded data:",
+ !!cached.uploadedPesData,
);
await refreshPatternInfo();
- return { pesData: cached.pesData, patternOffset: cached.patternOffset };
+ return {
+ pesData: cached.pesData,
+ uploadedPesData: cached.uploadedPesData,
+ patternOffset: cached.patternOffset,
+ patternRotation: cached.patternRotation,
+ };
}
return null;
diff --git a/src/stores/usePatternStore.ts b/src/stores/usePatternStore.ts
index 3e1a850..94f568b 100644
--- a/src/stores/usePatternStore.ts
+++ b/src/stores/usePatternStore.ts
@@ -21,6 +21,7 @@ interface PatternState {
setUploadedPattern: (
uploadedData: PesPatternData,
uploadedOffset: { x: number; y: number },
+ fileName?: string,
) => void;
clearUploadedPattern: () => void;
resetPatternOffset: () => void;
@@ -69,23 +70,32 @@ export const usePatternStore = create<PatternState>((set) => ({
setUploadedPattern: (
uploadedData: PesPatternData,
uploadedOffset: { x: number; y: number },
+ fileName?: string,
) => {
set({
uploadedPesData: uploadedData,
uploadedPatternOffset: uploadedOffset,
patternUploaded: true,
+ // Optionally set filename if provided (for resume/reconnect scenarios)
+ ...(fileName && { currentFileName: fileName }),
});
console.log("[PatternStore] Uploaded pattern set");
},
// Clear uploaded pattern (called when deleting from machine)
+ // This reverts to pre-upload state, keeping pesData so user can re-adjust and re-upload
clearUploadedPattern: () => {
+ console.log("[PatternStore] CLEARING uploaded pattern...");
set({
uploadedPesData: null,
uploadedPatternOffset: { x: 0, y: 0 },
patternUploaded: false,
+ // Keep pesData, currentFileName, patternOffset, patternRotation
+ // so user can adjust and re-upload
});
- console.log("[PatternStore] Uploaded pattern cleared");
+ console.log(
+ "[PatternStore] Uploaded pattern cleared - back to editable mode",
+ );
},
// Reset pattern offset to default
Served by rngit 1.3.3 - Generated in 0.13s